package com.tools.common.security.secret;

import com.tools.common.io.CharsetEnum;
import com.tools.common.object.Note;

import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * RSA 非对称加密算法的管理实例
 * */
@Note("RSA 非对称加密算法的管理实例")
public final class RSACypher implements TwoWayCypher {

    @Note("加密的公钥")
    private final PublicKey publicKey;

    @Note("解密的公钥")
    private final PrivateKey privateKey;

    @Note("默认的字符集")
    private final CharsetEnum charset;

    /* **************************************************************************************
     *
     *          构造器
     *
     * **************************************************************************************
     * */

    public RSACypher() {
        this(CharsetEnum.UTF_8);
    }

    public RSACypher(CharsetEnum charset) {
        private_checkCharsetEnum(charset);
        KeyPair keyPair = SecretKit.createRSAKeyPair();
        this.publicKey = keyPair.getPublic();
        this.privateKey = keyPair.getPrivate();
        this.charset = charset;
    }

    public RSACypher(KeyPair keyPair) {
        this(keyPair, CharsetEnum.UTF_8);
    }

    public RSACypher(KeyPair keyPair, CharsetEnum charset) {
        private_checkKeyPair(keyPair);
        private_checkCharsetEnum(charset);
        this.publicKey = keyPair.getPublic();
        this.privateKey = keyPair.getPrivate();
        this.charset = CharsetEnum.UTF_8;
    }

    public RSACypher(PublicKey publicKey, PrivateKey privateKey) {
        this(publicKey, privateKey, CharsetEnum.UTF_8);
    }

    public RSACypher(PublicKey publicKey, PrivateKey privateKey, CharsetEnum charset) {
        private_checkKeyPair(publicKey, privateKey);
        private_checkCharsetEnum(charset);
        this.publicKey = publicKey;
        this.privateKey = privateKey;
        this.charset = charset;
    }

    public RSACypher(String publicKey, String privateKey) {
        this(publicKey, privateKey, CharsetEnum.UTF_8);
    }

    public RSACypher(String publicKey, String privateKey, CharsetEnum charset) {
        private_checkKeyPair(publicKey, privateKey);
        private_checkCharsetEnum(charset);
        this.publicKey = SecretKit.toRSAPublicKey(publicKey);
        this.privateKey = SecretKit.toRSAPrivateKey(privateKey);
        this.charset = charset;
    }

    public PublicKey getPublicKey() {
        return publicKey;
    }

    public PrivateKey getPrivateKey() {
        return privateKey;
    }

    public CharsetEnum getCharset() {
        return charset;
    }

    /* **************************************************************************************
     *
     *          实现方法
     *
     * **************************************************************************************
     * */

    @Override
    public boolean isOneWay() {
        return false;
    }

    @Override
    public boolean isTwoWay() {
        return true;
    }

    @Override
    public String encrypt(String plaintext) {
        return SecretKit.encryptWithRSA(plaintext, this.publicKey, this.charset);
    }

    @Override
    public String decrypt(String ciphertext) {
        return SecretKit.decryptWithRSA(ciphertext, this.privateKey, this.charset);
    }

    @Override
    public String encrypt(String plaintext, CharsetEnum charset) {
        return SecretKit.encryptWithRSA(plaintext, this.publicKey, charset);
    }

    @Override
    public String decrypt(String ciphertext, CharsetEnum charset) {
        return SecretKit.decryptWithRSA(ciphertext, this.privateKey, charset);
    }

    /* **************************************************************************************
     *
     *          私有逻辑
     *
     * **************************************************************************************
     * */


    @Note("校验密钥对")
    private void private_checkKeyPair(KeyPair keyPair) {
        if(keyPair == null) throw new NullPointerException("RSA 非对称加密所需密钥对实例不能为 null");
    }

    @Note("校验密钥对")
    private void private_checkKeyPair(PublicKey publicKey, PrivateKey privateKey) {
        if(publicKey == null) throw new NullPointerException("RSA 非对称加密所需公钥不能为 null");
        if(privateKey == null) throw new NullPointerException("RSA 非对称加密所需私钥不能为 null");
    }

    @Note("校验密钥对")
    private void private_checkKeyPair(String publicKey, String privateKey) {
        if(publicKey == null) throw new NullPointerException("RSA 非对称加密所需公钥不能为空");
        if(privateKey == null) throw new NullPointerException("RSA 非对称加密所需私钥不能为空");
    }

    @Note("校验字符集枚举")
    private void private_checkCharsetEnum(CharsetEnum charset) {
        if(charset == null) throw new NullPointerException("字符集枚举为 null");
    }

}
